from flask import Flask, send_file, jsonify, request, send_from_directory
import pymongo
import json
from datetime import datetime
from bson.objectid import ObjectId
from flask_cors import CORS

with open("config.json") as config_file:
    config = json.load(config_file)

app = Flask(__name__)
CORS(app, origins="*")

mongo = pymongo.MongoClient(config["mongodb"])
db = mongo["word"]
word_sheets = db["word_sheets"]


def getWordNumber(id):
    # 转换字符串为ObjectId
    # document_id = ObjectId(id)

    # 聚合管道
    pipeline = [
        {"$match": {"_id": id}},
        {"$project": {"words_length": {"$size": "$words"}}},
    ]

    # 执行查询
    result = word_sheets.aggregate(pipeline)
    if doc := next(result, None):
        return doc["words_length"]


@app.route("/")
def index():
    return send_file("./word-remeber-client/dist/index.html")


@app.route("/assets/<path:filename>")
def static_files(filename):
    return send_from_directory("./word-remeber-client/dist/assets", filename)


# 创建空单词表
@app.route("/api/create_word_sheet", methods=["POST"])
def create_word_sheet():
    data = request.get_json()
    # 校验请求数据有效性
    if not data or "name" not in data:
        return jsonify({"message": 'Missing required field "name"'}), 400

    # 检查名称是否已存在
    existing = word_sheets.find_one({"name": data["name"]})
    if existing:
        return jsonify({"message": "Name already exists"}), 400

    try:
        # 插入新数据
        result = word_sheets.insert_one(
            {
                "name": data["name"],
                "words": [],
                "created_at": datetime.now(),
                "edit_at": datetime.now(),
            }
        )
    except Exception as e:
        # 处理数据库异常
        return jsonify({"message": "Internal server error"}), 500
    else:
        # 返回创建成功的资源 ID 及 201 状态码
        return jsonify({"id": str(result.inserted_id), "message": "创建成功"}), 201


# 更改单词
@app.route("/api/change_word", methods=["POST"])
def add_word():
    # 验证必要字段存在性
    data = request.get_json()
    if not data or "word_sheet_id" not in data or "word" not in data:
        return jsonify({"message": "缺少必要参数"}), 400

    # 验证字段类型
    if not isinstance(data["word"], list):
        return jsonify({"message": "word字段应为列表类型"}), 400

    try:
        obj_id = ObjectId(data["word_sheet_id"])
    except:  # 更精确的异常捕获
        return jsonify({"message": "Invalid ID format"}), 400

    try:
        # word_sheets.update_one({"_id":obj_id},
        #                       {"$push": {"words": {"$each": data['word']}}})
        # 更改word数组
        word_sheets.update_one(
            {"_id": obj_id},
            {"$set": {"words": data["word"], "edit_at": datetime.now()}},
        )
    except pymongo.errors.PyMongoError as e:  # 具体数据库异常捕获
        return jsonify({"message": "Internal server error"}), 500

    return jsonify({"message": "插入成功"}), 200


# 获取单词表列表
@app.route("/api/get_word_sheets", methods=["GET"])
def get_word_sheets():
    try:
        # 获取分页参数并校验
        page = int(request.args.get("page", 1))
        per_page = int(request.args.get("per_page", 10))

        if page < 1 or per_page < 1:
            return jsonify({"message": "Invalid pagination parameters"}), 400

        # 计算跳过的文档数量
        skip = (page - 1) * per_page

        # 执行分页查询（同时获取总数）
        total = word_sheets.count_documents({})
        cursor = (
            word_sheets.find({}, {"_id": 1, "name": 1, "created_at": 1, "edit_at": 1})
            .skip(skip)
            .limit(per_page)
        )

        # 转换ObjectId为字符串
        word_sheets_list = [
            {**doc, "_id": str(doc["_id"]), "count": getWordNumber(doc["_id"])}
            for doc in cursor
        ]

        # 构建分页元数据
        return (
            jsonify(
                {
                    "message": "获取成功",
                    "data": word_sheets_list,
                    "pagination": {
                        "total": total,
                        "page": page,
                        "per_page": per_page,
                        "total_pages": (total + per_page - 1) // per_page,
                    },
                }
            ),
            200,
        )

    except ValueError:
        return jsonify({"message": "Invalid parameter type"}), 400
    except Exception as e:
        return jsonify({"message": "Internal server error"}), 500


# 获取单词列表
@app.route("/api/get_words", methods=["POST"])
def get_words():
    data = request.get_json()

    try:
        cursor = word_sheets.find({"_id": ObjectId(data["id"])}, {"words": 1, "_id": 0})
    except:
        return jsonify({"message": "Internal server error"}), 500
    else:
        rsps_data = {
            "message": "Success",
            "words": [x for x in cursor][0]["words"],
            "count": getWordNumber(ObjectId(data["id"])),
            "id": data["id"],
            "name": "",
        }
        try:
            cursor = word_sheets.find(
                {"_id": ObjectId(data["id"])}, {"name": 1, "_id": 0}
            )
        except:
            return jsonify({"message": "Internal server error"}), 500
        else:
            rsps_data["name"] = [x for x in cursor][0]["name"]
            return jsonify(rsps_data), 200


# 删除单词表
@app.route("/api/delete_word_sheet", methods=["DELETE"])
def delete_word_sheet():
    data = request.get_json()
    # 校验数据有效性
    if not data["id"]:
        return jsonify({"message": "Invalid data"}), 400

    try:
        # word_sheets.delete_many({"_id":{"$in":data['id']}})
        word_sheets.delete_many({"_id": {"$in": [ObjectId(i) for i in data["id"]]}})
    except:
        return jsonify({"message": "Internal server error"}), 500
    else:
        return jsonify({"message": "Success"}), 200


# 搜索单词表
@app.route("/api/search_word_sheet", methods=["GET"])
def search_word_sheet():
    query = request.args.get("query", "")
    if not query:
        return jsonify({"message": "Query parameter is required"}), 400

    try:
        cursor = word_sheets.find(
            {"name": {"$regex": query, "$options": "i"}},
            {"_id": 1, "name": 1, "created_at": 1, "edit_at": 1},
        )
        results = [
            {**doc, "_id": str(doc["_id"]), "count": getWordNumber(doc["_id"])}
            for doc in cursor
        ]

    except Exception as e:
        return jsonify({"message": "Internal server error"}), 500

    return jsonify({"message": "Search successful", "data": results}), 200

if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=False)
